package com.intco.ait.quotation.api.starter.advice;

import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import java.util.Arrays;

/**
 * @author mxy
 */
@Slf4j
@Aspect
public class CommonLogAdvice {

    // 匹配所有 @Service 和 @RestController 注解的类
    @Pointcut("within(@org.springframework.stereotype.Service *) || within(@org.springframework.web.bind.annotation.RestController *)")
    public void serviceOrController() {
    }


    // MyBatis-Plus IService 相关切入点
    @Pointcut("within(com.baomidou.mybatisplus.extension.service.IService+)")
    public void mybatisPlusService() {
    }

    @Pointcut("!execution(* com.baomidou.mybatisplus.extension.service.IService.query(..))")
    public void excludeMybatisQuery() {
    }

    @Pointcut("!execution(* com.baomidou.mybatisplus.extension.service.IService.update(..))")
    public void excludeMybatisUpdate() {
    }

    // 组合所有切入点
    @Pointcut("(" +
            "serviceOrController() " +
            ")" +
            "｜｜ (" +
            "mybatisPlusService() " +
            "&& excludeMybatisQuery() " +
            "&& excludeMybatisUpdate()" +
            ")")
    public void combinedPointcut() {
    }


    public static String getThreadLogId() {
        return ThreadLogContext.getThreadLogId();
    }

    @Around("combinedPointcut()")
    public Object handleExceptionLog(ProceedingJoinPoint jp) throws Throwable {
        ThreadLogContext.setThreadLogId();
        try {
            log.info("[线程标识:{}] {}方法准备调用，参数: {}", ThreadLogContext.getThreadLogId(), jp.getSignature(), Arrays.toString(jp.getArgs()));
            long a = System.currentTimeMillis();
            Object result = jp.proceed();
            log.info("[线程标识:{}] {}方法调用成功，返回值{}，执行耗时{}", ThreadLogContext.getThreadLogId(), jp.getSignature(), JSON.toJSONString(result), System.currentTimeMillis() - a);
            return result;
        } catch (Throwable throwable) {
            log.error("[线程标识:{}] {}方法执行失败，原因：{}", ThreadLogContext.getThreadLogId(), jp.getSignature(), throwable.getMessage(), throwable);
            throw throwable;
        } finally {
            ThreadLogContext.removeThreadLogId();
        }
    }
}